#include "dxDraw.h"


////////////added 
#include "cube.h"
#include "ground.h"

#include "CollisionManager.h"

//new
#include "dxinput.h"

float vm_Y2 = 0.24;
float vm_X2 = 0.05;

float gravity2 = -0.00490;

float time_unit2 = 1;

///////////

LPDIRECT3D9             pD3D;
LPDIRECT3DDEVICE9       pd3dDevice;
D3DMATERIAL9            mtrl;

// camera variables
D3DXMATRIX matView;					// the view matrix
D3DXMATRIX matProj;					// the projection matrix
D3DXMATRIX matTran;					// the translation matrix

// more for ground
D3DXMATRIX matView2;					// the view matrix
D3DXMATRIX matProj2;					// the projection matrix
D3DXMATRIX matTran2;					// the translation matrix

D3DXVECTOR3 cameraPosition;			// the position of the camera
D3DXVECTOR3 cameraLook;				// where the camera is pointing

// vertex buffer
LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertices

// texture info
LPDIRECT3DTEXTURE9      g_pTexture   = NULL;
LPDIRECT3DTEXTURE9      g_pTexture2   = NULL;

// objects

cube  myCube1;
cube  myCube2;
cube  myCube3;
cube  myCube4;
ground myGround1;
ground myGround2;
ground myGround3;
CollisionManager colManager;

int GetSound = 0;
bool deadball = false;

void Create_DD(HWND &wndHandle)
{
	dxManager *dxMgr = new dxManager();
	dxMgr->init(wndHandle);

	// init direct3d
	initDirect3D(wndHandle);

	D3DXCreateTextureFromFile( pd3dDevice, "test.bmp", &g_pTexture );
	D3DXCreateTextureFromFile( pd3dDevice, "test2.bmp", &g_pTexture2 );
	pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );

	// setup the vertex buffer and add the triangle to it.
	SetupVB();
}

int Render(HINSTANCE &hInstance)
{
	GetSound = 0;
				//////////////////////////////

			XandY input;

			input = Get_Input(hInstance, myCube1.forceY, myCube1.forceX, myCube1.vi_Y, myCube1.vi_X, myCube1.transY, myCube1.transX);

			// call our render function
			pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );

			pd3dDevice->BeginScene();

			// draw the contents of the vertex buffer
			drawVB(g_pVB, input);
			
			pd3dDevice->EndScene();

			pd3dDevice->Present( NULL, NULL, NULL, NULL );
	return GetSound;
}

/*************************************************************************
* SetupVB
* Setup the vertex buffer
*************************************************************************/
HRESULT SetupVB()
{
	HRESULT hr;
	int vbcount = 0;

    // Initialize three vertices for rendering a triangle
	CUSTOMVERTEX g_Vertices[72] =
	{
		//{ 0.0f, 1.41f, 0.0f,  0.0f,0.0f },	// top
		//{ 1.0f, 0.0f, 1.0f,  1.0f,0.0f },	// beginning
		//{ 1.0f, 0.0f,-1.0f,  1.0f,0.0f },
		//{-1.0f, 0.0f,-1.0f,  1.0f,1.0f },
		//{-1.0f, 0.0f, 1.0f,  0.0f,1.0f },
		//{ 1.0f, 0.0f, 1.0f,  1.0f,0.0f },	// beginning
		//
		//{ 0.0f,-1.41f, 0.0f,  0.0f,0.0f },	// bottom
		//{ 1.0f, 0.0f, 1.0f,  1.0f,0.0f },	// beginning
		//{-1.0f, 0.0f, 1.0f,  0.0f,1.0f },
		//{-1.0f, 0.0f,-1.0f,  1.0f,1.0f },
		//{ 1.0f, 0.0f,-1.0f,  1.0f,0.0f },
		//{ 1.0f, 0.0f, 1.0f,  1.0f,0.0f },	// beginning

		//{-5.0f,-1.41f, 1.0f,  0.0f,0.0f },	// ground
		//{ 5.0f,-1.41f, 1.0f,  5.0f,0.0f },
		//{-5.0f,-1.41f,-1.0f,  0.0f,5.0f },
		//{ 5.0f,-1.41f,-1.0f,  5.0f,5.0f },
	};

		vbcount = 0;
	vbcount = myCube1.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myCube2.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myCube3.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myCube4.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myGround1.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myGround2.setupVB(&g_Vertices[vbcount],vbcount);
	vbcount = myGround3.setupVB(&g_Vertices[vbcount],vbcount);

	// populate the collision manager

	colManager.Enemies.appendNode(myCube1);
	colManager.Enemies.appendNode(myCube2);
	colManager.Enemies.appendNode(myCube3);
	colManager.Enemies.appendNode(myCube4);
	colManager.Platforms.appendNode(myGround1);
	colManager.Platforms.appendNode(myGround2);
	colManager.Platforms.appendNode(myGround3);

	// Create the vertex buffer
	g_pVB = createVertexBuffer(sizeof(g_Vertices) * sizeof(CUSTOMVERTEX), D3DFVF_CUSTOMVERTEX);

    // Fill the vertex buffer.
    VOID* pVertices;

	hr = g_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 );
	if FAILED (hr)
        return E_FAIL;

	// copy the vertices into the buffer
    memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );

	// unlock the vertex buffer
    g_pVB->Unlock();

    return S_OK;
}

/*************************************************************************
* initDirect3D
* initialize direct3D
*************************************************************************/
bool initDirect3D(HWND hwnd)
{
	HRESULT hr;

	if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		return false;
	}

	D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount  = 1;
	d3dpp.BackBufferHeight = 480;
	d3dpp.BackBufferWidth  = 640;
	d3dpp.hDeviceWindow    = hwnd;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	// create the direct3D device
    hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
                             D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                             &d3dpp, &pd3dDevice );
	if FAILED (hr)
    {
        return false;
    }

	return true;
}

/*************************************************************************
* createVertexBuffer
* creates the vertexbuffer
*************************************************************************/
LPDIRECT3DVERTEXBUFFER9 createVertexBuffer(int size, DWORD usage)
{
	HRESULT hr;
	LPDIRECT3DVERTEXBUFFER9 buffer;

    // Create the vertex buffer.
    hr = pd3dDevice->CreateVertexBuffer( size,
                                         0, 
										 usage,
                                         D3DPOOL_DEFAULT, 
										 &buffer, 
										 NULL );
	if FAILED ( hr)
        return NULL;
    
	return buffer;
}

/*************************************************************************
* drawVB
* draws the vertex buffer
*************************************************************************/
void drawVB(LPDIRECT3DVERTEXBUFFER9 buffer, XandY input)
{
	// create the camera
	createCamera(0.1f, 50.0f);		// near clip plane, far clip plane
	moveCamera(D3DXVECTOR3((input.transX / 2), 1.0f, -20.0f));
	pointCamera(D3DXVECTOR3((input.transX / 2), 0.0f, 0.0f));

	pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
    pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
	pd3dDevice->SetMaterial(&mtrl);

	//grounds
	D3DXMATRIX matRot2;

	//ground1
	D3DXMatrixRotationY(&matRot2, 0.0f);
	D3DXMATRIX matWorld2;
	D3DXMatrixTranslation(&matTran2, myGround1.transX, myGround1.transY, 0.0);
	D3DXMatrixMultiply(&matRot2, &matRot2, &matTran2);
	D3DXMatrixMultiply(&matWorld2, &matRot2, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld2 );
	myGround1.draw(&pd3dDevice, &g_pTexture2);

	//ground2
	D3DXMatrixRotationY(&matRot2, 0.0f);
	D3DXMatrixRotationX(&matRot2, 0.0f);
	D3DXMatrixRotationZ(&matRot2, 0.0f);
	D3DXMatrixTranslation(&matTran2, myGround2.transX, myGround2.transY, 0.0);
	D3DXMatrixMultiply(&matRot2, &matRot2, &matTran2);
	D3DXMatrixMultiply(&matWorld2, &matRot2, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld2 );
	myGround2.draw(&pd3dDevice, &g_pTexture2);

	//ground3
	D3DXMatrixRotationY(&matRot2, 0.0f);
	D3DXMatrixRotationX(&matRot2, 0.0f);
	D3DXMatrixRotationZ(&matRot2, 0.0f);
	D3DXMatrixTranslation(&matTran2, myGround3.transX, myGround3.transY, 0.0);
	D3DXMatrixMultiply(&matRot2, &matRot2, &matTran2);
	D3DXMatrixMultiply(&matWorld2, &matRot2, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld2 );
	myGround2.draw(&pd3dDevice, &g_pTexture2);

	//cubes
	D3DXMATRIX matRot;

	//cube 1

	// check object collision

	if(colManager.testObjectCollision(myCube1.ID))
	{
		D3DXMatrixRotationY(&matRot, 100);
		GetSound = 2;
	}
	else
	{
		D3DXMatrixRotationY(&matRot, 0);
	}

	// check platform colllision

	if(colManager.testGroundCollision(myCube1.ID))
	{
		GetSound = 1;
		//D3DXMatrixRotationY(&matRot, 0);
		myCube1.vi_Y *= -1;
		myCube1.transY += myCube1.vi_Y + 0.5 * (myCube1.forceY + gravity2) * time_unit2;
		myCube1.vi_Y = myCube1.vi_Y + gravity2 * time_unit2;
		/*myCube1.forceX
		if(vi_Y > vm_Y)
		{
			vi_Y = vm_Y;
		}
		transY += vi_Y + 0.5 * (forceY + gravity) * time_unit;
		vi_Y = vi_Y + gravity * time_unit;*/
	}
	else
	{
		//D3DXMatrixRotationY(&matRot, 0);
		if(myCube1.transY > -20)
		{
			if(myCube1.vi_Y > vm_Y2)
			{
				myCube1.vi_Y = vm_Y2;
			}
			myCube1.transY += myCube1.vi_Y + 0.5 * (myCube1.forceY + gravity2) * time_unit2;
			myCube1.vi_Y = myCube1.vi_Y + gravity2 * time_unit2;
		}
		else if(deadball == false)
		{
			deadball = true;
			GetSound = 3;
			if(myCube1.vi_Y > vm_Y2)
			{
				myCube1.vi_Y = vm_Y2;
			}
			myCube1.transY += myCube1.vi_Y + 0.5 * (myCube1.forceY + gravity2) * time_unit2;
			myCube1.vi_Y = myCube1.vi_Y + gravity2 * time_unit2;
		}
		else
		{
			if(myCube1.vi_Y > vm_Y2)
			{
				myCube1.vi_Y = vm_Y2;
			}
			myCube1.transY += myCube1.vi_Y + 0.5 * (myCube1.forceY + gravity2) * time_unit2;
			myCube1.vi_Y = myCube1.vi_Y + gravity2 * time_unit2;
		}
		
		if(myCube1.transY < -200)
		{
			GetSound = 4;
		}
	}
	
	D3DXMatrixTranslation(&matTran, myCube1.transX, myCube1.transY, 0.0);
	D3DXMatrixMultiply(&matRot, &matRot, &matTran);
	D3DXMATRIX matWorld;
	D3DXMatrixMultiply(&matWorld, &matRot, &matView);	
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
	pd3dDevice->SetTexture( 0, g_pTexture );
	pd3dDevice->SetStreamSource( 0, buffer, 0, sizeof(CUSTOMVERTEX) );
	myCube1.draw(&pd3dDevice, &g_pTexture2);

	//cube 2
	
	if(colManager.testGroundCollision(myCube2.ID))
	{
		D3DXMatrixRotationY(&matRot, 100);
		myCube2.vi_Y *= -1;
		myCube2.transY += myCube2.vi_Y + 0.5 * (myCube2.forceY + gravity2) * time_unit2;
		myCube2.vi_Y = myCube2.vi_Y + gravity2 * time_unit2;
	}
	else
	{
		D3DXMatrixRotationY(&matRot, 0);
		if(myCube2.vi_Y > vm_Y2)
		{
			myCube2.vi_Y = vm_Y2;
		}
		myCube2.transY += myCube2.vi_Y + 0.5 * (myCube2.forceY + gravity2) * time_unit2;
		myCube2.vi_Y = myCube2.vi_Y + gravity2 * time_unit2;

		myCube2.vi_X *= 0.98;

		myCube2.transX += myCube2.vi_X;
	}

	//myCube2.update();

	D3DXMatrixRotationY(&matRot, 0.0f);
	D3DXMatrixRotationX(&matRot, 0.0f);
	D3DXMatrixRotationZ(&matRot, 0.0f);
	D3DXMatrixTranslation(&matTran, myCube2.transX, myCube2.transY, 0.0);
	D3DXMatrixMultiply(&matRot, &matRot, &matTran);
	D3DXMatrixMultiply(&matWorld, &matRot, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
	pd3dDevice->SetTexture( 0, g_pTexture );
	pd3dDevice->SetStreamSource( 0, buffer, 0, sizeof(CUSTOMVERTEX) );
	myCube2.draw(&pd3dDevice, &g_pTexture2);

	//cube 3
	
	if(colManager.testGroundCollision(myCube3.ID))
	{
		D3DXMatrixRotationY(&matRot, 100);
		myCube3.vi_Y *= -1;
		myCube3.transY += myCube3.vi_Y + 0.5 * (myCube3.forceY + gravity2) * time_unit2;
		myCube3.vi_Y = myCube3.vi_Y + gravity2 * time_unit2;
	}
	else
	{
		D3DXMatrixRotationY(&matRot, 0);
		if(myCube3.vi_Y > vm_Y2)
		{
			myCube3.vi_Y = vm_Y2;
		}
		myCube3.transY += myCube3.vi_Y + 0.5 * (myCube3.forceY + gravity2) * time_unit2;
		myCube3.vi_Y = myCube3.vi_Y + gravity2 * time_unit2;

		myCube3.vi_X *= 0.98;

		myCube3.transX += myCube3.vi_X;
	}

	D3DXMatrixRotationY(&matRot, 0.0f);
	D3DXMatrixRotationX(&matRot, 0.0f);
	D3DXMatrixRotationZ(&matRot, 0.0f);
	D3DXMatrixTranslation(&matTran, myCube3.transX, myCube3.transY, 0.0);
	D3DXMatrixMultiply(&matRot, &matRot, &matTran);
	D3DXMatrixMultiply(&matWorld, &matRot, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
	pd3dDevice->SetTexture( 0, g_pTexture );
	pd3dDevice->SetStreamSource( 0, buffer, 0, sizeof(CUSTOMVERTEX) );
	myCube3.draw(&pd3dDevice, &g_pTexture2);

	//cube 4
	
	if(colManager.testGroundCollision(myCube4.ID))
	{
		D3DXMatrixRotationY(&matRot, 100);
		myCube4.vi_Y *= -1;
		myCube4.transY += myCube4.vi_Y + 0.5 * (myCube4.forceY + gravity2) * time_unit2;
		myCube4.vi_Y = myCube4.vi_Y + gravity2 * time_unit2;
	}
	else
	{
		D3DXMatrixRotationY(&matRot, 0);
		if(myCube4.vi_Y > vm_Y2)
		{
			myCube4.vi_Y = vm_Y2;
		}
		myCube4.transY += myCube4.vi_Y + 0.5 * (myCube4.forceY + gravity2) * time_unit2;
		myCube4.vi_Y = myCube4.vi_Y + gravity2 * time_unit2;

		myCube4.vi_X *= 0.98;

		myCube4.transX += myCube4.vi_X;
	}

	D3DXMatrixRotationY(&matRot, 0.0f);
	D3DXMatrixRotationX(&matRot, 0.0f);
	D3DXMatrixRotationZ(&matRot, 0.0f);
	D3DXMatrixTranslation(&matTran, myCube4.transX, myCube4.transY, 0.0);
	D3DXMatrixMultiply(&matRot, &matRot, &matTran);
	D3DXMatrixMultiply(&matWorld, &matRot, &matView);
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
	pd3dDevice->SetTexture( 0, g_pTexture );
	pd3dDevice->SetStreamSource( 0, buffer, 0, sizeof(CUSTOMVERTEX) );
	myCube4.draw(&pd3dDevice, &g_pTexture2);
}

/*************************************************************************
* shutdown
* shuts down and releases direct3D
*************************************************************************/
void shutdown(void)
{
    if( pd3dDevice != NULL) 
	{
        pd3dDevice->Release();
		pd3dDevice = NULL;
	}
    if( pD3D != NULL)
	{
        pD3D->Release();
		pD3D = NULL;
	}
}


/*************************************************************************
* createCamera
* creates a virtual camera
*************************************************************************/
void createCamera(float nearClip, float farClip)
{
	//Here we specify the field of view, aspect ration and near and far clipping planes.
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 640/480, nearClip, farClip);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

/*************************************************************************
* moveCamera
* moves the camera to a position specified by the vector passed as a 
* parameter
*************************************************************************/
void moveCamera(D3DXVECTOR3 vec)
{
	cameraPosition = vec;
}

/*************************************************************************
* pointCamera
* points the camera a location specified by the passed vector
*************************************************************************/
void pointCamera(D3DXVECTOR3 vec)
{
	cameraLook = vec;

	D3DXMatrixLookAtLH(&matView, &cameraPosition,		//Camera Position
                                 &cameraLook,			//Look At Position
                                 &D3DXVECTOR3(0.0f, 1.0f, 0.0f));		//Up Direction

	pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
}
void createLighting(void)
{
	 //set the ambient lighting
	pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255));
	pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);

	// Create and turn on a directional light
	D3DLIGHT9 light;
    D3DXVECTOR3 vDir( 1.0f, -1.0f, 0.0f );
    light.Type         = D3DLIGHT_SPOT;
    light.Diffuse.r  = 1.0f;
	light.Diffuse.g  = 0.5;
	light.Diffuse.b  = 0.5f;
    light.Ambient.r  = 0.5f;
	light.Ambient.g  = 0.5;
	light.Ambient.b  = 0.5f;
    D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vDir );
    light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
	light.Position     = D3DXVECTOR3( -250.0f, 250.0f, 0.0f );
    light.Range        = sqrtf(FLT_MAX);
	light.Phi		   = 1.0f;
	light.Falloff	   = 0.5f;
	light.Theta		   = 0.5f;
    pd3dDevice->SetLight(0, &light );
    pd3dDevice->LightEnable(0, TRUE );

	// Create and define the material
	ZeroMemory(&mtrl, sizeof(D3DMATERIAL9));
	mtrl.Diffuse.r = mtrl.Ambient.r = 0.5f;
	mtrl.Diffuse.g = mtrl.Ambient.g = 0.5f;
	mtrl.Diffuse.b = mtrl.Ambient.b = 0.9f;
	mtrl.Specular.r = 1.0f;
	mtrl.Specular.g = 0.3f;
	mtrl.Specular.b = 1.0f;
	mtrl.Power = 8.0f;	
}
